/**
 * WebRTC客户端
 * 用于通过WebRTC从设备服务器获取视频流和UI控件树
 * 
 * 注意：此类依赖于全局的 deviceSocket 实例（来自 socketio-client.js）
 * 复用已有的WebSocket连接，避免重复实现连接逻辑
 */

const DEFAULT_ICE_SERVERS = [
    { 'urls': 'stun:stun.l.google.com:19302' },
    { 'urls': 'stun:stun1.l.google.com:19302' },
    { 'urls': 'stun:stun2.l.google.com:19302' },
    { 'urls': 'stun:stun3.l.google.com:19302' },
    { 'urls': 'stun:stun4.l.google.com:19302' },
    {
        'urls': 'turn:172.16.1.84:3478',
        'username': 'smartest',
        'credential': 'smartest123'
    }
];

const WebRTCErrno = {
    ESOCK: 1,       // WebSocket不可用
    ECONN: 2,       // WebSocket未连接
    ETIMEOUT: 3,    // 超时
    EPEER: 4,       // 对端错误
    EINVAL: 5,      // 无效参数
    ESTATE: 6,      // WebRTC握手状态错误
    ESIGSVR: 7,     // 信令服务器出错
    ESRDP: 8,       // 设置远程描述出错
    EAICE: 9,       // 添加ICE候选出错
    EBUSY: 10,      // 忙，有信令请求在处理中
    ETRANSPORT: 11, // 信令服务器与设备服务器之间的传输错误
};

class WebRTCClient {
    /**
     * 创建WebRTC客户端实例
     * @param {Object} options - 配置选项
     * @param {string} options.deviceSn - 设备序列号
     * @param {string} options.host - 主机地址
     * @param {number} options.port - 端口号
     * @param {Function} options.onVideoFrame - 视频帧回调函数
     * @param {Function} options.onUiTree - UI树回调函数
     * @param {Function} options.onConnected - 连接成功回调函数
     * @param {Function} options.onDisconnected - 断开连接回调函数
     * @param {Function} options.onError - 错误回调函数
     */
    constructor(options) {
        this.deviceSn = options.deviceSn;
        this.host = options.host || window.location.hostname;
        this.port = options.port || (window.location.protocol === 'https:' ? 443 : 80);
        this.onVideoFrame = options.onVideoFrame || function() {};
        this.onUiTree = options.onUiTree || function() {};
        this.onPerfMetrics = options.onPerfMetrics || function() {};
        this.onConnected = options.onConnected || function() {};
        this.onDisconnected = options.onDisconnected || function() {};
        this.onError = options.onError || function() {};
        
        this.peerConnection = null;
        this.offer = null;
        this.videoChannel = null;
        this.uitreeChannel = null;
        this.uinputChannel = null;
        this.perfChannel = null;
        this.ctrlChannel = null;
        this.videoElement = null;
        this.connected = false;
        this.disconnecting = false;
        this.reconnectAttempts = 0;
        this.maxReconnectAttempts = 5;
        this.reconnectTimer = null;
        this.candidate_cache = [];
        this.signal_syn_seq = 0;    // 即将发送的信令序号
        this.signal_ack_seq = 0;    // 期待收到的信令序号
        
        // 初始化socket为null，在_initWebSocket中设置
        this.deviceSocket = null;
        // this.pendingRequests = new Map();
        this.pendingSignal = null;

        this.clientId = null;
        
        // ICE服务器配置
        this.iceServers = null;
    }
    
    /**
     * 检查WebRTC连接是否已建立
     * @returns {boolean} 连接状态
     */
    isConnected() {
        return this.connected && this.peerConnection !== null;
    }
    
    /**
     * 连接到设备服务器
     * @param {HTMLVideoElement} videoElement - 视频元素
     * @returns {Promise} 连接结果
     */
    webrtc_connect(videoElement) {
        // 1. 连接视频元素
        this.videoElement = videoElement;
        // 检查全局deviceSocket是否存在
        if (typeof deviceSocket === 'undefined') {
            this.onError('deviceSocket未定义，请确保已加载socketio-client.js');
            return;
        }
        
        // 2. 检查websocket状态和连接
        this.deviceSocket = deviceSocket;
        if (this.deviceSocket.connected) {
            console.log('WebSocket连接已建立');
            // 4. 初始化客户端ID
            this.clientId = this._createClientId();
            // 5. 设置WebRTC信号处理器
            this._setupWebRTCHandlers();
            // 6. 发送webrtc_ready信号开始建立P2P连接
            this._sendWebRTCSignal('webrtc_ready', {
                signal_syn_seq: this.signal_syn_seq,
                signal_ack_seq: this.signal_ack_seq,
                client_id: this.clientId, 
                device_sn: this.deviceSn,
            }).catch((error) => {
                this.onError('发送webrtc_ready信号失败: ' + error.errmsg);
                // 7. TODO：处理信令错误
            });
            return;
        }
        
        const connectHandler = () => {
            console.log('WebSocket连接已建立');
            // 4. 初始化客户端ID
            this.clientId = this._createClientId();
            // 5. 设置WebRTC信号处理器
            this._setupWebRTCHandlers();
            // 6. 发送webrtc_ready信号开始建立P2P连接
            this._sendWebRTCSignal('webrtc_ready', {
                signal_syn_seq: this.signal_syn_seq,
                signal_ack_seq: this.signal_ack_seq,
                client_id: this.clientId,
                device_sn: this.deviceSn,
            }).catch((error) => {
                this.onError('发送webrtc_ready信号失败: ' + error.errmsg);
                // 7. TODO：处理信令错误
            });
            this.deviceSocket.off('connect', connectHandler);
            this.deviceSocket.off('error', errorHandler);
        };
        
        const errorHandler = (error) => {
            console.error('WebSocket连接错误:', error);
            this.onError('WebSocket连接失败: ' + error);
            this.deviceSocket.off('connect', connectHandler);
            this.deviceSocket.off('error', errorHandler);
        };
        
        this.deviceSocket.on('connect', connectHandler);
        this.deviceSocket.on('error', errorHandler);
        
        // 3. 如果WebSocket未连接，先建立WebSocket连接
        if (!this.deviceSocket.connected) {
            this.deviceSocket.connect();
        }
    }

    /**
     * 断开WebRTC连接
     */
    async webrtc_disconnect() {
        // 1. 设置断开标志以通知异步任务停止信令交换
        this.disconnecting = true;
        // 2. 等待已经开始的信令处理完成，最多等待5秒
        const maxWaitTime = 5000; // 5秒超时
        const checkInterval = 100; // 每100ms检查一次
        let waitTime = 0;
        while (this.pendingSignal !== null && waitTime < maxWaitTime) {
            await new Promise(resolve => setTimeout(resolve, checkInterval));
            waitTime += checkInterval;
        }
        // 3. 如果所有信令处理完成，发送webrtc_disconnect信号通知对端关闭
        if (this.pendingSignal === null) {
            response = await this._sendWebRTCSignal('webrtc_disconnect', {
                signal_syn_seq: this.signal_syn_seq,
                signal_ack_seq: this.signal_ack_seq,
                client_id: this.clientId,
                device_sn: this.deviceSn,
            });
            if (response.status === 'err') {
                this.onError('WebSocket disconnect error: ' + response.errmsg || '未知错误');
            }
        }
        // 4. 无论对端是否收到断开信号，都要关闭本地WebRTC连接并释放资源
        this._cleanup();
        this.reconnectAttempts = 0;
        // 5. 断开WebSocket连接
        if (this.deviceSocket) {
            try {
                this.deviceSocket.disconnect();
            } catch (error) {
                this.onError('WebSocket disconnect error: ' + error);
                this.onDisconnected();
                return Promise.reject({ 
                    status: 'err', 
                    errnum: WebRTCErrno.ESOCK, 
                    errmsg: error.message || 'WebSocket disconnect error',
                });
            }
        }
        this.onDisconnected();
        return Promise.resolve({ status: 'ok' });
    }

    /**
     * 清理连接资源
     * @private
     */
    _cleanup() {
        // 1. 清理重连定时器
        if (this.reconnectTimer) {
            clearTimeout(this.reconnectTimer);
            this.reconnectTimer = null;
        }
        // 2. 关闭数据通道
        if (this.uitreeChannel) {
            this.uitreeChannel.close();
            this.uitreeChannel = null;
        }
        if (this.uinputChannel) {
            this.uinputChannel = null;
        }
        if (this.perfChannel) {
            this.perfChannel.close();
            this.perfChannel = null;
        }
        if (this.ctrlChannel) {
            this.ctrlChannel.close();
            this.ctrlChannel = null;
        }
        // 3. 关闭对等连接
        if (this.peerConnection) {
            this.peerConnection.close();
            this.peerConnection = null;
        }
        // 4. 清理待处理的信令
        this.pendingSignal = null;
        // 5. 重置连接状态
        this.connected = false;
        this.disconnecting = false;
    }

    /**
     * 生成客户端ID
     * @private
     * @returns {string} 唯一的客户端ID
     */
    _createClientId() {
        // 使用时间戳和随机数生成唯一ID
        const timestamp = Date.now().toString(36);
        const randomStr = Math.random().toString(36).substring(2, 8);
        return `webrtc_client_${timestamp}_${randomStr}`;
    }

    /**
     * 匹配请求信令和响应信令
     * @private
     * @param {Object} reqSignal - 请求信令
     * @param {string} type - 响应信令
     * @param {Object} data - 响应数据
     * @returns {boolean} 是否匹配
     */
    _matchSignals(reqSignal, type, data) {
        if (reqSignal === null) {
            return false;
        }
        if (type === 'webrtc_error' && reqSignal.type !== data.source) {
                return false;
        }
        if ((reqSignal.type !== type) && (reqSignal.type !== 'webrtc_offer' || type !== 'webrtc_answer')) {
            return false;
        }
        if (reqSignal.data.client_id !== data.client_id) {
            return false;
        }
        if (reqSignal.data.device_sn !== data.device_sn) {
            return false;
        }
        if (reqSignal.data.signal_ack_seq !== data.signal_syn_seq) {
            return false;
        }
        if ((reqSignal.data.signal_syn_seq + 1) !== data.signal_ack_seq) {
            return false;
        }
        return true;
    }

    /**
     * 比较两个信令是否相同
     * @private
     * @param {Object} srcSignal - 源信令
     * @param {string} type - 响应信令
     * @param {Object} data - 响应数据
     * @returns {boolean} 是否相同
     */
    _compSignals(srcSignal, type, data) {
        if (srcSignal.type !== type) {
            return false;
        }
        if (srcSignal.data.client_id !== data.client_id) {
            return false;
        }
        if (srcSignal.data.device_sn !== data.device_sn) {
            return false;
        }
        if (srcSignal.data.signal_syn_seq !== data.signal_syn_seq) {
            return false;
        }
        if (srcSignal.data.signal_ack_seq !== data.signal_ack_seq) {
            return false;
        }
        return true;
    }

    /**
     * 通过WebSocket发送请求
     * @private
     * @param {string} type - 操作类型
     * @param {Object} data - 请求数据
     * @returns {Promise<Object>} 响应结果
     */
    _sendWebRTCSignal(type, data) {
        return new Promise((resolve, reject) => {
            // 1. 检查WebSocket对象是否有效
            if (!this.deviceSocket || !this.deviceSocket.socket) {
                reject({
                    status: 'err',
                    errnum: WebRTCErrno.ESOCK,
                    errmsg: 'WebSocket is not available'});
                return;
            }
            // 2. 检查WebSocket连接状态
            if (!this.deviceSocket.connected) {
                reject({
                    status: 'err',
                    errnum: WebRTCErrno.ECONN,
                    errmsg: 'WebSocket is not connected'});
                return;
            }
            // 3. 检查是否有待处理的信令请求
            if (this.pendingSignal !== null) {
                reject({
                    status: 'err',
                    errnum: WebRTCErrno.EBUSY,
                    errmsg: 'WebRTC request is pending'});
                return;
            }
            // 4. 检查是否正在关闭WebRTC连接
            if (this.disconnecting === true && type !== 'webrtc_disconnect') {
                reject({
                    status: 'err',
                    errnum: WebRTCErrno.ESTATE,
                    errmsg: 'WebRTC is disconnecting'});
                return;
            }
            // 5. 存储信令消息处理器
            this.pendingSignal = {
                type: type,
                data: data,
                resolve: resolve,
                reject: reject,
            }
            // 6. 发射WebRTC请求信号
            try {
                this.deviceSocket.socket.emit(type, data);
            } catch (error) {
                reject({
                    status: 'err',
                    errnum: WebRTCErrno.ESOCK,
                    errmsg: 'WebSocket emit error'});
                this.pendingSignal = null;
                return;
            }
            // 7. 设置超时
            setTimeout(() => {
                if (this.pendingSignal && this._compSignals(this.pendingSignal, type, data)) {
                    reject({
                        status: 'err',
                        errnum: WebRTCErrno.ETIMEOUT,
                        errmsg: 'WebRTC request timeout'});
                    this.pendingSignal = null;
                    return;
                }
            }, 10000); // 10秒超时
        });
    }

    /**
     * 设置WebRTC相关的事件处理器
     * @private
     */
    _setupWebRTCHandlers() {
        // 1. 移除之前注册的事件处理器以避免一个事件触发多次
        this.deviceSocket.socket.off('webrtc_ready');
        this.deviceSocket.socket.off('webrtc_answer');
        this.deviceSocket.socket.off('webrtc_candidate');
        this.deviceSocket.socket.off('webrtc_disconnect');
        this.deviceSocket.socket.off('webrtc_error');

        // 2. 监听webrtc_ready响应信号
        this.deviceSocket.socket.on('webrtc_ready', (data) => {
            console.log('webrtc_ready消息: ', data);
            // 1) 检查响应与请求是否匹配
            if (!this._matchSignals(this.pendingSignal, 'webrtc_ready', data)) {
                // 正常情况下信令不匹配是由于待决请求被超时处理掉之后产生了新的待决请求，
                // 然后超时请求的响应信令到达，但是待决请求已经被新的请求替换，
                // 所以这里需要忽略超时请求的响应信令。
                console.warn('webrtc ready signals mismtach: syn_seq=', this.pendingSignal.data.signal_syn_seq, 'ack_seq=', data.signal_ack_seq);
                return;
            }
            // 2) 更新信令序号: 只要请求和响应匹配就要更新信令序号确保每一个信令都可以用序号唯一标识
            this.signal_syn_seq = data.signal_ack_seq;
            this.signal_ack_seq = data.signal_syn_seq + 1;
            // 3) 处理匹配的信令响应
            const resolve = this.pendingSignal.resolve;
            const reject = this.pendingSignal.reject;
            if (data.ice_servers && 
                Array.isArray(data.ice_servers) && 
                data.ice_servers.length > 0) {
                this.iceServers = data.ice_servers;
            } else {
                this.iceServers = DEFAULT_ICE_SERVERS;
            }
            // 4) 完成信令处理
            resolve({ status: 'ok' });
            this.pendingSignal = null;
            // 5) 发起下一轮请求
            this._initPeerConnection();
            this._createOffer();
        });

        // 监听webrtc_answer响应信号
        this.deviceSocket.socket.on('webrtc_answer', async (data) => {
            console.log('webrtc_answer消息: ', data);
            // 1) 检查响应与请求是否匹配
            if (!this._matchSignals(this.pendingSignal, 'webrtc_answer', data)) {
                // 正常情况下信令不匹配是由于待决请求被超时处理掉之后产生了新的待决请求，
                // 然后超时请求的响应信令到达，但是待决请求已经被新的请求替换，
                // 所以这里需要忽略超时请求的响应信令。
                console.warn('webrtc offer/answer signals mismtach: syn_seq=', this.pendingSignal.data.signal_syn_seq, 'ack_seq=', data.signal_ack_seq);
                return;
            }
            // 2) 更新信令序号
            this.signal_syn_seq = data.signal_ack_seq;
            this.signal_ack_seq = data.signal_syn_seq + 1;
            // 3) 处理匹配的信令响应
            const resolve = this.pendingSignal.resolve;
            const reject = this.pendingSignal.reject;
            try {
                await this.peerConnection.setRemoteDescription(data.answer);
            } catch (error) {
                // 4) 完成请求处理
                reject({
                    status: 'err',
                    errnum: WebRTCErrno.ESRDP,
                    errmsg: error.message
                });
                this.pendingSignal = null;
                return;
            }
            // 4) 完成请求处理
            resolve({ status: 'ok' });
            this.pendingSignal = null;
            // 5) 发起下一轮请求
            let signalData = {
                signal_syn_seq: this.signal_syn_seq,
                signal_ack_seq: this.signal_ack_seq,
                client_id: this.clientId,
                device_sn: this.deviceSn,
                candidate: null,
                syn_seq: 0, // 即将发送的ICE候选的序列号
                ack_seq: 0, // 期望收到的ICE候选的序列号
            };
            if (this.candidate_cache.length > 0) {
                signalData.candidate = this.candidate_cache[0];
            }
            const sendCandidate = (signalData, retryCount = 0) => {
                if (this.connected || this.disconnecting) {
                    // 信令交换只发生在WebRTC连接建立过程中，连接建立完成后就不再交换信令
                    // 如果正在断开连接，则只能交换webrtc_disconnect信令
                    return;
                }
                this._sendWebRTCSignal('webrtc_candidate', signalData)
                    .catch((error) => {
                        this.onError('发送ICE候选失败: ' + error.errmsg);
                        // 特别注意这里地失败包含了发送和应答失败，因此不能简单地认为当前candidate没有被
                        // 对端添加成功，这里不加区分地重新发送可能会导致对端收到并重复添加相同的candidate。
                        // 然而这并不会导致故障，如果想要避免重复添加相同的candidate，可以在对端添加去重逻辑。
                        // TODO: 根据错误类型决定是否重试
                        if (retryCount < 3) {
                            console.error('发送ICE候选失败，正在重试第' + (retryCount + 1) + '次');
                            setTimeout(() => {
                                sendCandidate(signalData, retryCount + 1);
                            }, 1000 * (retryCount + 1));
                        } else {
                            console.error('发送ICE候选失败，已达到最大重试次数');
                        }
                    });
            }
            sendCandidate(signalData);
        });

        // 监听WebRTC设备服务器端candidate信号
        this.deviceSocket.socket.on('webrtc_candidate', async (data) => {
            console.log('webrtc_candidate消息: ', data);
            // 1) 检查响应与请求是否匹配
            if (!this._matchSignals(this.pendingSignal, 'webrtc_candidate', data)) {
                // 正常情况下信令不匹配是由于待决请求被超时处理掉之后产生了新的待决请求，
                // 然后超时请求的响应信令到达，但是待决请求已经被新的请求替换，
                // 所以这里需要忽略超时请求的响应信令。
                console.warn('webrtc candidate signals mismtach: syn_seq=', this.pendingSignal.data.signal_syn_seq, 'ack_seq=', data.signal_ack_seq);
                return;
            }
            // 2) 更新信令序号
            this.signal_syn_seq = data.signal_ack_seq;
            this.signal_ack_seq = data.signal_syn_seq + 1;
            // 3) 处理匹配的信令响应
            const resolve = this.pendingSignal.resolve;
            const reject = this.pendingSignal.reject;
            // 添加ICE候选
            let add_candidate_success = false;
            if (data.candidate) {
                try {
                    await this.peerConnection.addIceCandidate(data.candidate);
                    add_candidate_success = true;
                } catch (error) {
                    // 4) 完成请求处理
                    reject({
                        status: 'err',
                        errnum: WebRTCErrno.EAICE,
                        errmsg: error.message
                    });
                    this.pendingSignal = null;
                    return;
                }
            }
            // 4) 完成请求处理
            resolve({ status: 'ok' });
            this.pendingSignal = null;
            // 5) 发起下一轮请求
            let signalData = {
                signal_syn_seq: this.signal_syn_seq,
                signal_ack_seq: this.signal_ack_seq,
                client_id: this.clientId,
                device_sn: this.deviceSn,
                candidate: null,
                // 即将发送的ICE候选的序列号
                syn_seq: data.ack_seq,
                // 期望收到的ICE候选的序列号
                ack_seq: add_candidate_success ? data.syn_seq + 1 : data.syn_seq,
            };
            if (this.candidate_cache.length > signalData.syn_seq) {
                signalData.candidate = this.candidate_cache[signalData.syn_seq];
            }
            const sendCandidate = (signalData, retryCount = 0) => {
                if (this.connected || this.disconnecting) {
                    // 信令交换只发生在WebRTC连接建立过程中，连接建立完成后就不再交换信令
                    // 如果正在断开连接，则只能交换webrtc_disconnect信令
                    return;
                }
                this._sendWebRTCSignal('webrtc_candidate', signalData)
                    .catch((error) => {
                        this.onError('发送ICE候选失败: ' + error.errmsg);
                        // 特别注意这里地失败包含了发送和应答失败，因此不能简单地认为当前candidate没有被
                        // 对端添加成功，这里不加区分地重新发送可能会导致对端收到并重复添加相同的candidate。
                        // 然而这并不会导致故障，如果想要避免重复添加相同的candidate，可以在对端添加去重逻辑。
                        // TODO: 根据错误类型决定是否重试
                        if (retryCount < 3) {
                            console.error('发送ICE候选失败，正在重试第' + (retryCount + 1) + '次');
                            setTimeout(() => {
                                sendCandidate(signalData, retryCount + 1);
                            }, 1000 * (retryCount + 1));
                        } else {
                            console.error('发送ICE候选失败，已达到最大重试次数');
                        }
                    });
            }
            sendCandidate(signalData);
        });

        // 监听WebRTC设备服务器端disconnect信号
        this.deviceSocket.socket.on('webrtc_disconnect', (data) => {
            console.log('webrtc_disconnect消息: ', data);
            // 1) 检查响应与请求是否匹配
            if (!this._matchSignals(this.pendingSignal, 'webrtc_disconnect', data)) {
                // 正常情况下信令不匹配是由于待决请求被超时处理掉之后产生了新的待决请求，
                // 然后超时请求的响应信令到达，但是待决请求已经被新的请求替换，
                // 所以这里需要忽略超时请求的响应信令。
                console.warn('webrtc disconnect signals mismtach: syn_seq=', this.pendingSignal.data.signal_syn_seq, 'ack_seq=', data.signal_ack_seq);
                return;
            }
            // 2) 更新信令序号
            this.signal_syn_seq = data.signal_ack_seq;
            this.signal_ack_seq = data.signal_syn_seq + 1;
            // 3) 处理匹配的信令响应: 无需任何处理
            const resolve = this.pendingSignal.resolve;
            // 4) 完成请求处理
            resolve({ status: 'ok' });
            this.pendingSignal = null;
            // 5) 信令交换结束，不再发送信令
        });

        // 监听WebRTC设备服务器端error信号
        this.deviceSocket.socket.on('webrtc_error', (data) => {
            console.log('webrtc_error消息: ', data);
            // 1) 检查响应与请求是否匹配
            if (!this._matchSignals(this.pendingSignal, 'webrtc_error', data)) {
                // 正常情况下信令不匹配是由于待决请求被超时处理掉之后产生了新的待决请求，
                // 然后超时请求的响应信令到达，但是待决请求已经被新的请求替换，
                // 所以这里需要忽略超时请求的响应信令。
                console.warn('webrtc error signals mismtach: syn_seq=', this.pendingSignal.data.signal_syn_seq, 'ack_seq=', data.signal_ack_seq);
                return;
            }
            // 2) 更新信令序号
            this.signal_syn_seq = data.signal_ack_seq;
            this.signal_ack_seq = data.signal_syn_seq + 1;
            // 3) 处理匹配的信令响应: 无需任何处理
            const reject = this.pendingSignal.reject;
            // 4) 完成请求处理
            reject({
                status: 'err',
                errnum: data.errnum,
                errmsg: data.errmsg
            });
            this.pendingSignal = null;
            // 5) 信令交换结束，不再发送信令
        });
    }

    /**
     * 初始化PeerConnection
     * @private
     */
    _initPeerConnection() {
        this.peerConnection = new RTCPeerConnection({
            iceServers: this.iceServers
        });

        // 创建UI控件树数据通道
        this._setupUiTreeChannel();

        // 创建输入事件数据通道
        this._setupUInputChannel();

        // 创建性能指标数据通道
        this._setupPerfChannel();

        // 创建控制指令数据通道
        this._setupCtrlChannel();

        // 处理接收到的数据通道
        this.peerConnection.ondatachannel = (event) => {
            const channel = event.channel;
            channel.onmessage = (event) => {
                console.log(`收到消息: ${event.data}`, 'success');
            };
        };

        // 处理远程视频流
        this.peerConnection.ontrack = (event) => {
            console.log(`收到远程视频流: ${event.streams.length}个流, ${event.track.kind}轨道`, 'success');
            if (event.streams && event.streams.length > 0) {
                this.videoElement.srcObject = event.streams[0];
                console.log(`视频元素srcObject已设置`, 'info');
                
                // 添加视频元素事件监听
                this.videoElement.onloadedmetadata = () => {
                    console.log('视频元数据已加载');
                };
                
                this.videoElement.onplay = () => {
                    console.log('视频开始播放', );
                };
                
                this.videoElement.onerror = (error) => {
                    console.log('视频播放错误: ' + error);
                };
            } else {
                console.log('没有接收到视频流');
            }
        };
        
        // 处理ICE候选
        this.peerConnection.onicecandidate = (event) => {
            if (event.candidate) {
                // 缓存本地ICE候选等待合适地时机发送到对端以保证时序
                this.candidate_cache.push(event.candidate);
            }
        };
                
        // 连接状态变化
        this.peerConnection.onconnectionstatechange = () => {
            const state = this.peerConnection.connectionState;
            console.log(`WebRTC连接状态: ${state}`, 'info');
            if (state === 'connected') {
                console.log('WebRTC P2P连接建立成功', 'success');
                this.connected = true;
                // TODO: 处理连接成功逻辑
            } else if (state === 'disconnected' || state === 'failed') {
                console.log('WebRTC连接断开');
                this.connected = false;
                // TODO: 处理连接断开逻辑
            }
        };
    }

    /**
     * 设置UI树数据通道
     * @private
     */
    _setupUiTreeChannel() {
        this.uitreeChannel = this.peerConnection.createDataChannel('uitree', { ordered: true });
        
        this.uitreeChannel.onopen = () => {
            console.log('UI树数据通道已打开', 'success');
        };

        this.uitreeChannel.onmessage = (event) => {
            const data = JSON.parse(event.data);
            console.log(`收到UI树数据: ${data}`, 'success');
            this.onUiTree(data);
        };
        
        this.uitreeChannel.onclose = () => {
            console.log('UI树数据通道已关闭', 'info');
        };

        this.uitreeChannel.onerror = (error) => {
            console.error('UI树数据通道错误:', error);
        };
    }

    /**
     * 设置输入事件数据通道
     * @private
     */
    _setupUInputChannel() {
        this.uinputChannel = this.uitreeChannel;
    }

    /**
     * 设置性能指标数据通道
     * @private
     */
    _setupPerfChannel() {
        this.perfChannel = this.peerConnection.createDataChannel('perf', { ordered: true });
        
        this.perfChannel.onopen = () => {
            console.log('性能指标数据通道已打开', 'success');
        };

        this.perfChannel.onmessage = (event) => {
            const data = JSON.parse(event.data);
            console.log(`收到性能指标数据: ${data}`, 'success');
            this.onPerfMetrics(data);
        };
        
        this.perfChannel.onclose = () => {
            console.log('性能指标数据通道已关闭', 'info');
        };

        this.perfChannel.onerror = (error) => {
            console.error('性能指标数据通道错误:', error);
        };
    }

    /**
     * 设置控制指令数据通道
     * @private
     */
    _setupCtrlChannel() {
        this.ctrlChannel = this.perfChannel;
    }

    /**
     * 创建Offer
     * @private
     */
    async _createOffer() {
        try {
            // 先创建一个虚拟的视频流
            const canvas = document.createElement('canvas');
            canvas.width = 640;
            canvas.height = 480;
            const ctx = canvas.getContext('2d');
            ctx.fillStyle = 'black';
            ctx.fillRect(0, 0, 640, 480);
            
            const stream = canvas.captureStream(1);
            const videoTrack = stream.getVideoTracks()[0];
            
            // 添加视频轨道到PeerConnection
            const sender = this.peerConnection.addTrack(videoTrack, stream);
            console.log(`添加虚拟视频轨道: ${videoTrack.kind}`, 'info');
            
            // 立即移除轨道，但保留transceiver用于接收
            this.peerConnection.removeTrack(sender);
            
            // 设置transceiver方向为recvonly
            const transceivers = this.peerConnection.getTransceivers();
            transceivers.forEach((t, i) => {
                if (t.receiver.track && t.receiver.track.kind === 'video') {
                    t.direction = 'recvonly';
                    console.log(`设置视频transceiver ${i}方向为: ${t.direction}`, 'info');
                }
            });
            
            console.log(`当前transceivers数量: ${transceivers.length}`, 'info');

            // 创建offer
            const offer = await this.peerConnection.createOffer();
            this.offer = offer;
            await this.peerConnection.setLocalDescription(offer);
            
            console.log(`创建offer成功: type=${offer.type}, sdp长度=${offer.sdp.length}`, 'info');
            
            // 检查SDP是否包含视频
            const hasVideo = offer.sdp.includes('m=video');
            console.log(`offer是否包含视频: ${hasVideo}`, hasVideo ? 'success' : 'error');
            
            if (hasVideo) {
                console.log('✅ offer包含视频媒体描述', 'success');
            } else {
                console.log('❌ offer不包含视频媒体描述', 'error');
                console.log(`完整SDP: ${offer.sdp}`, 'error');
            }
            // 发送offer
            if (this.connected === false && this.disconnecting === false) {
                this._sendWebRTCSignal('webrtc_offer', {
                    signal_syn_seq: this.signal_syn_seq,
                    signal_ack_seq: this.signal_ack_seq,
                    client_id: this.clientId,
                    device_sn: this.deviceSn,
                    offer: offer 
                }).catch((error) => {
                        this.onError('发送webrtc_offer信号失败: ' + error.errmsg);
                        // TODO: 处理发送offer失败的情况
                    });

                console.log('发送Offer', 'info');
            }
        } catch (error) {
            console.log(`创建offer失败: ${error.message}`, 'error');
            console.error('createOffer error:', error);
        }
    }
}